import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable, of} from 'rxjs';
import {JsonResult} from '../model/JsonResult';
import * as gc from 'src/app/global/const';
import {UUID} from 'angular2-uuid';
import {DatePipe} from '@angular/common';
import {TableStyle, TableStyleService} from './table-style.service';
import {map} from 'rxjs/operators';
import {ArrayutilsService} from './arrayutils.service';
import {SelectedRow} from '../global/model';
import {ENUM_MOVE} from '../global/enum';

@Injectable({
  providedIn: 'root'
})
export class LifeScheduleService {


  private path_pre = 'lifeSchedule';
  private tableName:string = 'life_schedule';
  private tableStyle:TableStyle[] = [];
  tableData:LifeSchedule[] = [];
  tableData_onGoing:LifeSchedule[] = []; // 进行中的日程 - 表格组件绑定的数据源
  tableData_onGoing_ori:LifeSchedule[] = []; // 进行中的日程
  tableData_finished:LifeSchedule[] = []; // 结束的日程
  tableStyleMap:{[key:string]:TableStyle} = {};

  cache:{
    detail:{ [key:string]:{ edit:boolean,data:LifeSchedule } }
  } = {
    'detail':{}
  }

  selectedRow:SelectedRow = null;

  //#region 请求后端的URL
  private url = {
    'deleteByPrimaryKey':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre,
    'selectByPrimaryKey':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/selectByPrimaryKey',
    'selectAll':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/selectAll',
    'saveOne':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre,
    'insert':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/insert',
    'update':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/update',
    'updateSeq':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/updateSeq',
  }
  //#endregion

  //#region 构造方法
  constructor(
    private http:HttpClient,
    private datePipe:DatePipe,
    private tableStyleService:TableStyleService,
    private arrUtils:ArrayutilsService
  ) {
    this.tableStyleService.selectByTableName(this.tableName).subscribe(
      ( res:JsonResult ) => {
        if( res.code !==1 ){
          console.log(res.msg);
        }

        this.tableStyle = res.data;
        this.initTableStyleMap();
      },error => console.log('获取表' + this.tableName + '的样式时出现异常！')
    )
  }
  //#endregion

  //#region 将表格样式数据数组变形为MAP
  initTableStyleMap(){
    if( !this.tableStyle ) return;
    this.tableStyleMap = {};
    this.tableStyle.forEach(ele => {
      this.tableStyleMap[ele.field_name] = ele;
    });
  }
  //#endregion

  //#region 请求后端 - 根据主键删除 - 返回可观察对象
  deleteByPrimaryKey(iid:number):Observable<JsonResult>{
    const url = this.url.deleteByPrimaryKey + '/' + iid;
    return this.http.delete<JsonResult>(url);
  }
  //#endregion

  //#region 请求后端 - 根据主键查询行数据 - 返回可观察对象
  selectByPrimaryKey(iid:number):Observable<JsonResult>{
    const url = this.url.selectByPrimaryKey + '/' + iid;
    return this.http.get<JsonResult>(url);
  }
  //#endregion

  //#region 请求后端 - 更新排序序号 - 只更新进行中的
  updateSeq():Observable<JsonResult>{
    if( !this.tableData_onGoing ) return of(new JsonResult());
    this.tableData_onGoing.forEach((item,index,arr)=>{
      item.seq = index;
    })
    console.log('即将更新后端的数据是：');
    console.log(this.tableData_onGoing);
    return this.http.put(this.url.updateSeq,this.tableData_onGoing).pipe(map(
      (jr:JsonResult) =>{
        if( jr.code !==1 ) return jr;
        return jr;
      }
    ));
  }
  //#endregion

  //#region 查询获取所有数据 - 按照 seq 正序,iid 倒序,update_time 倒序排序
  private selectAll():Observable<JsonResult>{
    return this.http.get<JsonResult>(this.url.selectAll).pipe(map(
      ( jr:JsonResult ) =>{
        if( jr.code !==1 ) return jr;// 请求后端数据出错，原样返回数据
        this.resetSelectedRow();// 重置选中行
        const data:LifeSchedule[] = jr.data;
        jr.data = this.transData(data);
        return jr;
      }
    ));
  }
  //#endregion

  //#region 将数据变形后返回
  transData(data:LifeSchedule[]):LifeSchedule[]{
    data.sort(
      (a,b)=>{
        const dataA:Date = new Date(a.create_time);
        const dataB:Date = new Date(b.create_time);

        return dataA < dataB ? 1:0;
      }
    )

    data.forEach(ele => {
      ele.uuid = UUID.UUID();
    });

    this.tableData_finished = data.filter( item => item.finished === 1 );
    this.tableData_onGoing = data.filter( item => item.finished === 0 );
    this.tableData_onGoing_ori = data.filter( item => item.finished === 0 );
    return data;
  }
  //#endregion

  //#region 保存一行数据 - 新增或者修改
  saveOne(record:LifeSchedule):Observable<JsonResult>{
    record = this.tease(record);
    console.log('即将要保存的行数据是：');
    console.log(record);
    if( record.iid === undefined || record.iid === null || record.iid<=0 )
      return this.insert(record);
    else
      return this.update(record);
  }
  //#endregion

  //#region 新增一行数据
  insert(record:LifeSchedule):Observable<JsonResult>{
    record = this.tease(record);
    return this.http.post<JsonResult>(this.url.insert,record);
  }
  //#endregion

  //#region 修改一行数据
  update(record:LifeSchedule):Observable<JsonResult>{
    record = this.tease(record);
    return this.http.put<JsonResult>(this.url.update,record);
  }
  //#endregion

  // 将日期类型的字段转换为 Date 类型之后再转换为 DB 端设置的日期格式
  // 目的为防止后端做反序列化时由于日期格式不对导致转换失败报错
  tease(record:LifeSchedule):LifeSchedule{
    if( this.tableStyle === undefined || this.tableStyle === null || this.tableStyle.length<=0 ) return
    this.tableStyle.forEach(ele => {
      if( ele.tease.length !== undefined && ele.tease.length !== null && ele.tease.length>0 ){
        let fieldName:string = ele.field_name;
        if( record[fieldName] ) {
          let tmp:Date = new Date(record[fieldName]);
          record[fieldName] = this.datePipe.transform(tmp,ele.tease);
        }
      }
    });
    return record;
  }

  /**
   * 删除属性 tableData_onGoing 指定的行
   * @param rowIndex 数组序号
   * @param uuid uuid
   */
  deleteRow_front(rowIndex:number){
    this.tableData_onGoing = this.tableData_onGoing.filter(
      ( val,index,array ) =>{
        return index !== rowIndex;
      }
     )
  }

  //#region 新增一个空行
  addEmptyRow(){
    let record:LifeSchedule = new LifeSchedule();
    let uuid:string = record.uuid;
    this.cache.detail[uuid] = {
      edit:true,data:record
    };

    let newArray:LifeSchedule[] = [];
    newArray.push(record);
    this.tableData_onGoing = newArray.concat(this.tableData_onGoing);
    // this.tableData_onGoing = this.tableData_onGoing.concat(record);
  }
  //#endregion

  //#region 使用真实数据更新编辑用缓存数据
  updateEditCache(){
    this.tableData_onGoing.forEach(
      (ele:LifeSchedule) => {
        this.cache.detail[ele.uuid] = {
          edit:false,data:{...ele}
        }
    });
  }
  //#endregion

  //#region 刷新，重新从后端获取数据
  refresh():Observable<JsonResult>{
    return this.selectAll().pipe(map(
      ( jr:JsonResult ) =>{
        if( jr.code !==1 ) return jr;
        const data:LifeSchedule[] = jr.data;
        jr.data = this.transData(data);
        this.updateEditCache();
        return jr;
      }
    ))
  }
  //#endregion

  //#region 将已经完成的日程转换为进行中状态
  turn2Ing(rowIndex:number,uuid:string):Observable<JsonResult>{
    let data:LifeSchedule = this.tableData_finished[rowIndex];
    data.finished = 0;
    return this.update(data).pipe(map(
      ( jr:JsonResult ) =>{
        if( jr.code !==1 ) return jr;
        // 修改成功后更新UI
        const data = jr.data;
        this.tableData_finished = this.tableData_finished.filter( item => item.uuid !==uuid );
        this.tableData_onGoing = this.tableData_onGoing.concat(data);
        this.updateEditCache();
        return jr;
      }
    ))
  }
  //#endregion

  //#region 保存编辑状态 - 前后端都保存
  saveEdit(rowIndex:number,uuid:string):Observable<JsonResult>{
    let record:LifeSchedule = this.cache.detail[uuid].data;
    return this.saveOne(record).pipe(map(
      ( jr:JsonResult ) =>{
        if( jr.code !==1 ) return jr;

        let newRecord:LifeSchedule = jr.data;
        newRecord.uuid = UUID.UUID();
        if( newRecord.finished ===1 ){
          this.tableData_onGoing = this.tableData_onGoing.filter( item => item.uuid !==uuid );
          this.tableData_finished = this.tableData_finished.concat(newRecord);
        }else{
          this.tableData_onGoing = this.arrUtils.replace(this.tableData_onGoing,rowIndex,newRecord);
        }
        this.updateEditCache();
        this.cache.detail[newRecord.uuid].edit = false;
        return jr;
      }
    ))

  }
  //#endregion

  //#region 过滤内容列
  filterContent(content:string){
    console.log('即将过滤：' + content);
    if( !content ) this.tableData_onGoing = this.tableData_onGoing_ori.filter( item => 1===1 );
    this.tableData_onGoing = this.tableData_onGoing_ori.filter( item => {
      const exist:boolean = item.content.includes(content);
      console.log(item);
      console.log('模糊查询的结果是：' + exist);
      return exist;
    });
  }
  //#endregion

  //#region 设置选中行
  setSelectedRow(rowIndex:number,uuid:string){
    this.selectedRow = new SelectedRow();
    this.selectedRow.rowIndex = rowIndex;
    this.selectedRow.uuid = uuid;
  }
  //#endregion

  //#region 重置选中行
  resetSelectedRow(){
    this.selectedRow = null;
  }
  //#endregion

  //#region 获取当前选中的行
  getSelectedRow():SelectedRow{
    return this.selectedRow === undefined ? null:this.selectedRow;
  }
  //#endregion

  //#region 移动元素 - 向上
  movePrevious(){
    this.move(ENUM_MOVE.movePrevious);
  }
  //#endregion

  //#region 移动元素 - 向下
  moveNext(){
    this.move(ENUM_MOVE.moveNext);
  }
  //#endregion

  //#region 移动元素 - 第一
  moveFirst(){
    this.move(ENUM_MOVE.moveFirst);
  }
  //#endregion

  //#region 移动元素 - 最后
  moveLast(){
    this.move(ENUM_MOVE.moveLast);
  }
  //#endregion


  private move(direction:ENUM_MOVE){
    if( !this.selectedRow ) return;
    const index:number = this.selectedRow.rowIndex;

    //#region 移动元素并且重新设置当前选中行
    let newIndex:number = 0;
    switch (direction) {
      case ENUM_MOVE.moveFirst:
        //#region 移动元素
        this.tableData_onGoing = this.arrUtils.moveFirst<LifeSchedule>(this.tableData_onGoing,index);
        //#endregion
        //#region 重新设置当前选中行
        newIndex = 0;
        if( newIndex >=0 ){
          this.selectedRow = new SelectedRow();
          this.selectedRow.rowIndex = newIndex;
          this.selectedRow.uuid = this.tableData_onGoing[newIndex].uuid;
        }
        //#endregion
        break;
      case ENUM_MOVE.movePrevious:
        //#region 移动元素
        this.tableData_onGoing = this.arrUtils.movePrevious<LifeSchedule>(this.tableData_onGoing,index);
        //#endregion
        //#region 重新设置当前选中行
        newIndex = this.selectedRow.rowIndex - 1;
        if( newIndex >=0 ){
          this.selectedRow = new SelectedRow();
          this.selectedRow.rowIndex = newIndex;
          this.selectedRow.uuid = this.tableData_onGoing[newIndex].uuid;
        }
        //#endregion
        break;
      case ENUM_MOVE.moveNext:
        //#region 移动元素
        this.tableData_onGoing = this.arrUtils.moveNext<LifeSchedule>(this.tableData_onGoing,index);
        //#endregion
        //#region 重新设置当前选中行
        newIndex = this.selectedRow.rowIndex + 1;
        if( newIndex >=0 && newIndex<=this.tableData_onGoing.length-1 ){
          this.selectedRow = new SelectedRow();
          this.selectedRow.rowIndex = newIndex;
          this.selectedRow.uuid = this.tableData_onGoing[newIndex].uuid;
        }
        //#endregion
        break;
      case ENUM_MOVE.moveLast:
        //#region 移动元素
        this.tableData_onGoing = this.arrUtils.moveLast<LifeSchedule>(this.tableData_onGoing,index);
        //#endregion
        //#region 重新设置当前选中行
        newIndex = this.tableData_onGoing.length-1;
        if( newIndex >=0 ){
          this.selectedRow = new SelectedRow();
          this.selectedRow.rowIndex = newIndex;
          this.selectedRow.uuid = this.tableData_onGoing[newIndex].uuid;
        }
        //#endregion
        break;
    }
    //#endregion

    //#region 使用当前前端的表格数据数组的顺序向后端更新排序序号
    this.updateSeq().subscribe(
      (jr:JsonResult) =>{
        console.log('向后端更新排序序号成功');
      },error => console.log('更新排序序号时出现异常！')
    )
    //#endregion
  }
}


// Author：chanchaw
// Generator Version：1.0 - 2019年11月16日 16点46分
// This Model Created：Mon Jan 13 2020 21:29:43 GMT+0800 (中国标准时间)
export class LifeSchedule{
  //#region 属性
  iid:number;
  type:string;
  content:string;
  create_time:string;
  dead_line:string;
  progress:number;
  finished:number;
  finished_time:string;
  uuid:string;
  seq:number;
  //#endregion

  constructor(){
    this.uuid = UUID.UUID();
  }

}
